package com.droidblackbox.manager;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

import android.app.Activity;
import android.content.Context;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.util.Log;

import com.droidblackbox.exception.MapException;

public final class MapManager {

	public static final int ERROR = -1;
	public static final int ERROR_NETWORK = 0x100000;
	public static final int ERROR_LOCATION = 0x100001;
	public static final int OUT_OF_SERVICE = 0x100011;
	public static final int TEMPORARILY_UNAVAILABLE = 0x100111;
	public static final int AVAILABLE = 0x100110;

	private static final int TO_INT_DOUBLE_VALUE = 1000000;

	private static final String LOCATION_NOT_SERVICE = "Service Not Ready";
	private static final String LOCATION_ON_SERVICE = "Service Ready";

	private static MapManager instance = null;

	private final String LOG_TAG = "GetLocation";

	private int errorCode = 0;

	private Activity activity = null;

	private Location location = null;
	private LocationManager locationManager = null;
	private Criteria criteria = null;

	private String address = null;
	private String provider;

	private boolean isGpsCheck = true;

	public synchronized static MapManager setInstance(Activity activity) {
		if (instance == null) {
			synchronized (MapManager.class) {
				if (instance == null) {
					instance = new MapManager(activity);
				}
			}
		}

		return getInstance();
	}

	public synchronized static MapManager getInstance() {
		if (instance == null)
			return null;
		return instance;
	}

	private MapManager() {
	}

	/**
	 * 
	 * @class Location Manager
	 */
	private MapManager(Activity activity) {
		this.activity = activity;
		locationManager = (LocationManager) activity
				.getSystemService(Context.LOCATION_SERVICE);

		criteria = new Criteria();
		criteria.setAccuracy(Criteria.ACCURACY_FINE);
		criteria.setPowerRequirement(Criteria.POWER_LOW);
		criteria.setAltitudeRequired(false);
		criteria.setCostAllowed(false);

	}

	public void onLocation() {
		try {
			setProvider();
			if (location == null) {
				errorCode = ERROR_NETWORK;
			}
		} catch (Exception e) {
		}
	}

	private void setProvider() {
		boolean b = SystemManager.getInstance().isGps();

		provider = LocationManager.NETWORK_PROVIDER;
		if (b == true) {
			if (isGpsCheck == true) {
				provider = LocationManager.GPS_PROVIDER;
				locationManager
						.requestLocationUpdates(provider, 0, 0, listener);
				location = locationManager.getLastKnownLocation(provider);

				isGpsCheck = false;
			} else {
				provider = LocationManager.GPS_PROVIDER;
				locationManager
						.requestLocationUpdates(provider, 0, 0, listener);
				location = locationManager.getLastKnownLocation(provider);
			}
		} else {
			locationManager.requestLocationUpdates(provider, 0, 0, listener);
			location = locationManager.getLastKnownLocation(provider);
		}
	}

	public void removeUpdate() {
			locationManager.removeUpdates(listener);
	}

	public void startGetLocation() throws MapException {
		if (locationManager != null) {
			locationManager.addNmeaListener(gpsStatusNmeaListener);
		}
	}

	public void stopGetLocation() throws MapException {
		locationManager.removeNmeaListener(gpsStatusNmeaListener);
	}

	/**
	 * 
	 * @param startLatitude
	 * @param startLongitude
	 * @param endLatitude
	 * @param endLongitude
	 * @param results
	 */
	public void getDistanceBetween(double startLatitude, double startLongitude,
			double endLatitude, double endLongitude, float[] results) {

		if (getInstance().location != null) {
			Location.distanceBetween(startLatitude, startLongitude,
					endLatitude, endLongitude, results);
		}
	}

	public String getAddress() {
		return address;
	}

	public double getLatitudeDouble() {
		if (location != null)
			return location.getLatitude();
		return ERROR;
	}

	public double getLongitudeDouble() {
		if (location != null)
			return location.getLongitude();
		return ERROR;
	}

	public double getTimeDouble() {
		if (location != null)
			return location.getTime();
		return ERROR;
	}

	public int getLatitudeInt() {
		if (location != null)
			return (int) (location.getLatitude() * TO_INT_DOUBLE_VALUE);
		return ERROR;
	}

	public int getLongitudeInt() {
		if (location != null)
			return (int) (location.getLongitude() * TO_INT_DOUBLE_VALUE);
		return ERROR;
	}

	public int getTimeInt() {
		if (location != null)
			return (int) (location.getTime() * TO_INT_DOUBLE_VALUE);
		return ERROR;
	}

	public int getErrorCode() {
		return errorCode;
	}

	/**
	 * 
	 * Location Listener
	 * 
	 */

	private LocationListener listener = new LocationListener() {

		public void onProviderDisabled(String provider) {
			address = LOCATION_NOT_SERVICE;

		}

		public void onProviderEnabled(String provider) {
			address = LOCATION_ON_SERVICE;

		}

		public void onStatusChanged(String provider, int status, Bundle extras) {
			switch (status) {
			case LocationProvider.OUT_OF_SERVICE:
				errorCode = OUT_OF_SERVICE;
				break;
			case LocationProvider.TEMPORARILY_UNAVAILABLE:
				errorCode = TEMPORARILY_UNAVAILABLE;
				break;
			case LocationProvider.AVAILABLE:
				errorCode = AVAILABLE;
				break;
			}
			Log.e("Status Changed", errorCode + "");
		}

		public void onLocationChanged(Location location) {
			try {

				Geocoder geocoder = new Geocoder(activity, Locale.KOREA);
				List<Address> addresses = geocoder.getFromLocation(
						location.getLatitude(), location.getLongitude(), 1);

				address = addresses.get(0).getAddressLine(0);

				isGpsCheck = true;

			} catch (IOException e) {
				e.printStackTrace();
			}

		}
	};

	private GpsStatus.NmeaListener gpsStatusNmeaListener = new GpsStatus.NmeaListener() {

		public void onNmeaReceived(long timestamp, String nmea) {
			// $GPGGA,054208.000,3725.973,N,12709.561,E,1,05(수신된 위성
			// 갯수),1.90,141.50,M,160.50,M,,*58
			Log.d(LOG_TAG, nmea); // NMEA 값 확인.
			String str_temp[] = nmea.split(","); // 각 필드 ","로 구분.
			if (str_temp[0].equals("$GPGGA")) { // NMEA 값중 "$GPGGA"에 gps 위성수
				// 들어옴.
				Log.d(LOG_TAG, str_temp[7]); // 수신된 위성수 확인.
			}
		}
	};
}
